package com.dj.mingkong.common.util;


import com.dj.mingkong.common.exception.BizException;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.Map.Entry;
import java.util.function.BiConsumer;

public class UrlBuilder {
    private final Map<String, String> params = new LinkedHashMap(7);
    private String baseUrl;

    private UrlBuilder() {
    }

    public void setBaseUrl(String baseUrl) {
        this.baseUrl = baseUrl;
    }

    public static UrlBuilder fromBaseUrl(String baseUrl) {
        UrlBuilder builder = new UrlBuilder();
        builder.setBaseUrl(baseUrl);
        return builder;
    }

    public Map<String, Object> getReadOnlyParams() {
        return Collections.unmodifiableMap(this.params);
    }

    public UrlBuilder queryParam(String key, Object value) {
        if (StringUtils.isEmpty(key)) {
            throw new RuntimeException("参数名不能为空");
        } else {
            String valueAsString = value != null ? value.toString() : null;
            this.params.put(key, valueAsString);
            return this;
        }
    }

    public String build() {
        return this.build(false);
    }

    public String build(boolean encode) {
        if (MapUtils.isEmpty(this.params)) {
            return this.baseUrl;
        } else {
            String baseUrl = appendIfNotContain(this.baseUrl, "?", "&");
            String paramString = parseMapToString(this.params, encode);
            return baseUrl + paramString;
        }
    }

    private static String parseMapToString(Map<String, String> params, boolean encode) {
        List<String> paramList = new ArrayList();
        forEach(params, (k, v) -> {
            if (v == null) {
                paramList.add(k + "=");
            } else {
                paramList.add(k + "=" + (encode ? urlEncode(v) : v));
            }

        });
        return String.join("&", paramList);
    }

    private static String urlEncode(String value) {
        if (value == null) {
            return "";
        } else {
            try {
                String encoded = URLEncoder.encode(value, StandardCharsets.UTF_8.displayName());
                return encoded.replace("+", "%20").replace("*", "%2A").replace("~", "%7E").replace("/", "%2F");
            } catch (UnsupportedEncodingException var2) {
                throw new BizException("Failed To Encode Uri", var2);
            }
        }
    }

    public static <K, V> void forEach(Map<K, V> map, BiConsumer<K, V> action) {
        if (!MapUtils.isEmpty(map) && action != null) {
            Iterator var2 = map.entrySet().iterator();

            while (var2.hasNext()) {
                Entry entry = (Entry) var2.next();

                try {
                    K k = (K) entry.getKey();
                    V v = (V) entry.getValue();
                    action.accept(k, v);
                } catch (IllegalStateException var6) {
                    throw new ConcurrentModificationException(var6);
                }
            }
        }

    }

    public static String appendIfNotContain(String str, String appendStr, String otherwise) {
        if (!StringUtils.isEmpty(str) && !StringUtils.isEmpty(appendStr)) {
            return str.contains(appendStr) ? str.concat(otherwise) : str.concat(appendStr);
        } else {
            return str;
        }
    }
}
